﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Configuration;
using System.Diagnostics;
using System.Windows.Media.Animation;
using Microsoft.Samples.WindowsAzure.ServiceManagement;
using WAPA.Framework;
using System.IO;
using MultithreadBinding;
using System.Collections.ObjectModel;
using System.Windows.Threading;

using System.ComponentModel;

namespace WAPA.Client
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        BackgroundWorker worker;
        DispatcherTimer refreshOperationsTimer;
        DispatcherTimer refreshOutputTimer;
        WAPAClientViewModel viewModel;
        List<OperationContext> _list;


        public MainWindow()
        {
            refreshOperationsTimer = new System.Windows.Threading.DispatcherTimer();
            refreshOperationsTimer.Interval = new TimeSpan(0, 0, 0, 3, 0);
            refreshOperationsTimer.Tick += new EventHandler(refreshOperationsTimer_Tick);

            refreshOutputTimer = new System.Windows.Threading.DispatcherTimer();
            refreshOutputTimer.Interval = new TimeSpan(0, 0, 0, 7, 0);
            refreshOutputTimer.Tick += new EventHandler(refreshOutputTimer_Tick);

            worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = true;
            worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
            {
                if (e.Cancelled)
                {
                    WAPA.Framework.OperationContext operationContext = new WAPA.Framework.OperationContext("Task stopped");
                    operationContext.Completed = true;
                    ManagementContext.AddOperationContext(operationContext);
                }
            };
            worker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
           
                while (true)
                {
                    if (worker.CancellationPending == true)
                    {
                        args.Cancel = true;
                        break;
                    }

                    if (ManagementContext.Operations.Count == 0) continue;

                    ManagementContext.LockOperations();

                    foreach (OperationContext operationContext in ManagementContext.Operations)
                    {
                        if (operationContext.Completed == false && operationContext.TrackingId != null)
                        {
                            Operation operation = CloudServiceManager.GetOperationStatus(operationContext.TrackingId);

                            if (operation == null) continue;

                            operationContext.Status = operation.Status;

                            if (operation.Error != null) operationContext.ErrorMessage = operation.Error.Code + ":" + operation.Error.Message;

                            operationContext.Completed = (operation.Status == "Succeeded");

                            ManagementContext.UpdateOperationContext(operationContext);
                        }
                    }

                    ManagementContext.UnLockOperations();

                    System.Threading.Thread.Sleep(2000);
                }
            };

            StartBackgroundMonitoring();

            //Load the config in the ManagementContext for direct access.
            ManagementContext.SubscriptionId = ConfigurationManager.AppSettings["SubscriptionId"];//"efb150a3-d5c2-420c-b8dd-57811042f801";
            ManagementContext.AccountQuotaHostedServices = TryToParseInt(ConfigurationManager.AppSettings["AccountQuotaHostedServices"]);
            ManagementContext.AccountQuotaCores = TryToParseInt(ConfigurationManager.AppSettings["AccountQuotaCores"]);
            ManagementContext.AccountQuotaStorage = TryToParseInt(ConfigurationManager.AppSettings["AccountQuotaStorage"]);
            ManagementContext.CertificateThumbprint = ConfigurationManager.AppSettings["CertificateThumbprint"];// "6FCC1FC9332C851EAAD8E1DE63DBA1C40433AC5F";
            ManagementContext.AccessKey = ConfigurationManager.AppSettings["AccessKey"];
            ManagementContext.StorageAccountName = ConfigurationManager.AppSettings["StorageAccountName"];
            ManagementContext.CertificatePrivateKeyPassword = ConfigurationManager.AppSettings["CertificatePrivateKeyPassword"];
            ManagementContext.WorkerConfigFile = ConfigurationManager.AppSettings["WorkerConfigFile"];
            ManagementContext.WorkerConfig = File.ReadAllText(ManagementContext.WorkerConfigFile);
            ManagementContext.PackageContainerName = ConfigurationManager.AppSettings["PackageContainerName"];
            ManagementContext.PackageBlobName = ConfigurationManager.AppSettings["PackageBlobName"];
            ManagementContext.PackageFileName = ConfigurationManager.AppSettings["PackageFileName"];
            ManagementContext.PackageFileFolder = ConfigurationManager.AppSettings["PackageFileFolder"];
            ManagementContext.OutputContainerName = ConfigurationManager.AppSettings["OutputContainerName"];
            ManagementContext.ExecutionAssemblyLocation = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            ManagementContext.PiCalculatorBinariesLocation = ConfigurationManager.AppSettings["PiCalculatorBinariesLocation"];
            ManagementContext.Locations = new LocationList { new Location { Name = "Anywhere US" }, new Location { Name = "South Central US" }, new Location { Name = "Anywhere Europe" }, new Location { Name = "North Europe" }, new Location { Name = "West Europe" }, new Location { Name = "Anywhere Asia" }, new Location { Name = "Southeast Asia" }, new Location { Name = "East Asia" } };
            ManagementContext.certificate = CloudServiceManager.GetCertificate(ManagementContext.CertificateThumbprint);

            ManagementContext.OperationAdded += (e) =>
            {
                _list = new List<OperationContext>();

                foreach (OperationContext operationContext in ManagementContext.Operations)
                {
                    _list.Add(operationContext);
                }
            };


            InitializeComponent();

            vmSizeDropDown.SelectedIndex = 1;

            pendingTasks.ItemsSource = _list;

            //pendingTasks.ItemsSource = ManagementContext.Responses;

            viewModel = new WAPAClientViewModel();
            viewModel.Locations = ManagementContext.Locations;
            viewModel.SubscriptionId = ManagementContext.SubscriptionId;
            viewModel.CertificateThumbprint = ManagementContext.CertificateThumbprint;
            viewModel.AccessKey = ManagementContext.AccessKey;
            viewModel.StorageAccountName = ManagementContext.StorageAccountName;
            viewModel.CertificatePrivateKeyPassword = ManagementContext.CertificatePrivateKeyPassword;
            viewModel.WorkerConfigFile = ManagementContext.WorkerConfigFile;
            viewModel.Operations = ManagementContext.Operations;

            root.DataContext = viewModel;

            locationsListBox.SelectionChanged += (s_, ea) =>
            {
                //Check the maximum number of hosted services allowed for the account.
                if (locationsListBox.SelectedItems.Count > ManagementContext.AccountQuotaHostedServices) locationsListBox.SelectedItems.RemoveAt(locationsListBox.SelectedItems.Count - 2);

                if (locationsListBox.SelectedItems.Count > 0) setupTopologyButton.IsEnabled = true;
            };

            precision.PreviewKeyUp += (a, b) =>
            {

                int result = 0;
                bool numeric = int.TryParse(precision.Text, out result);

                if (!numeric) b.Handled = true;
            };
        }

        void refreshOutputTimer_Tick(object sender, EventArgs e)
        {
            //(root.DataContext as WAPAClientViewModel).RegisteredInstances = CloudServiceManager.GetQueueMessages<WorkerRegistrationMessage>(ManagementContext.RegistrationQueueName);
            //(root.DataContext as WAPAClientViewModel).Reports = CloudServiceManager.GetQueueMessages<WorkerTaskReportMessage>(ManagementContext.ReportQueueName);
            //(root.DataContext as WAPAClientViewModel).OutputBlobs = CloudServiceManager.GetBlobs(ManagementContext.OutputContainerName);

            this.registeredInstancesListBox.ItemsSource = CloudServiceManager.GetQueueMessages<WorkerRegistrationMessage>(ManagementContext.RegistrationQueueName);
            this.reportsListBox.ItemsSource = CloudServiceManager.GetQueueMessages<WorkerTaskReportMessage>(ManagementContext.ReportQueueName);
            this.outputBlobsListBox.ItemsSource = CloudServiceManager.GetBlobs(ManagementContext.OutputContainerName);
        }

        void refreshOperationsTimer_Tick(object sender, EventArgs e)
        {
            (root.DataContext as WAPAClientViewModel).Operations = ManagementContext.Operations;
            this.pendingTasks.ItemsSource = null;
            this.pendingTasks.ItemsSource = ManagementContext.Operations;
        }

        private static int TryToParseInt(string value)
        {
            int number;
            bool result = Int32.TryParse(value, out number);
            if (result)
            {
                return number;
            }
            else
            {
                if (value == null) value = "";
                return 10;
            }
        }

        /// <summary>
        /// Called when the expander opens and some async actions need to be done.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FillHostedServices(object sender, RoutedEventArgs e)
        {
            BackgroundWorker getHostedServicesWorker = new BackgroundWorker();

            hostedServicesListBox.SelectionChanged += (s, ea) =>
            {
                //Since we have default task settings 1 or more service selections can already enable the execute button.
                if (ea.AddedItems.Count > 0)
                    deployCalculationServicesButton.IsEnabled = true;
            };

            getHostedServicesWorker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                //Get the service we can deploy package to.
                viewModel.HostedServices = (HostedServiceList)CloudServiceManager.GetHostedServicesWithDetails();
            };

            getHostedServicesWorker.RunWorkerCompleted += (s, ea) =>
            {
                hostedServicesListBox.ItemsSource = viewModel.HostedServices;
                hostedServicesListBoxOverlay.Visibility = System.Windows.Visibility.Hidden;
            };


            hostedServicesListBoxOverlay.Visibility = System.Windows.Visibility.Visible;
            getHostedServicesWorker.RunWorkerAsync();

        }

        /// <summary>
        /// Setup the calculation action.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DeployCalculationServices(object sender, RoutedEventArgs e)
        {
            deployCalculationServicesButton.IsEnabled = false;


            HostedServiceList hostedServices = new HostedServiceList();

            foreach (HostedService hostedService in hostedServicesListBox.SelectedItems)
            {
                hostedServices.Add(hostedService);
            }

            DeploymentSlots deploymentSlot = (DeploymentSlots)Enum.Parse(typeof(DeploymentSlots), ((ComboBoxItem)slotDropDown.SelectedItem).Content as string);

            VMSizes vmSize = (VMSizes)Enum.Parse(typeof(VMSizes), vmSizeDropDown.SelectedValue as string);

            int noInstances = int.Parse(((ComboBoxItem)noInstancesDropDown.SelectedValue).Content as string);

            ScenarioManager.DeployCalculationServices(hostedServices, deploymentSlot, vmSize, noInstances);
        }

        private void FillDeployments(object sender, RoutedEventArgs e)
        {
            BackgroundWorker getDeploymentsWorker = new BackgroundWorker();

            deploymentsListBox.SelectionChanged += (s, ea) =>
            {
                if (ea.AddedItems.Count > 0)
                    sendTasksButton.IsEnabled = true;
            };

            getDeploymentsWorker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                //Get the active deployments to send messages for.
                viewModel.Deployments = (DeploymentList)CloudServiceManager.GetDeployments();
            };

            getDeploymentsWorker.RunWorkerCompleted += (s, ea) =>
            {
                deploymentsListBox.ItemsSource = viewModel.Deployments;
                deploymentsListBoxOverlay.Visibility = System.Windows.Visibility.Hidden;
            };

            deploymentsListBoxOverlay.Visibility = System.Windows.Visibility.Visible;
            getDeploymentsWorker.RunWorkerAsync();

        }



        private void SendTasks(object sender, RoutedEventArgs e)
        {
            sendTasksButton.IsEnabled = false;

            DeploymentList deployments = new DeploymentList();
            foreach (Deployment deployment in deploymentsListBox.SelectedItems)
            {
                deployments.Add(deployment);
            }

            ScenarioManager.SendCalculationTasks(deployments, int.Parse(precision.Text), int.Parse(repeatCount.Text),int.Parse(repeatInterval.Text));
        }

        /// <summary>
        /// Setup the topology action.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SetupTopology(object sender, RoutedEventArgs e)
        {
            setupTopologyButton.IsEnabled = false;

            LocationList locations = new LocationList();
            foreach (Location location in locationsListBox.SelectedItems)
            {
                locations.Add(location);
            }

            ScenarioManager.SetupTopology(locations);
        }

        private void Quit(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void Start(object sender, RoutedEventArgs e)
        {
            configOverlay.Visibility = System.Windows.Visibility.Hidden;
        }

        private void StartBackgroundMonitoring()
        {
            if (worker.IsBusy)
            {
                worker.CancelAsync();
            }
            else
            {
                worker.RunWorkerAsync();

                refreshOperationsTimer.Start();
                refreshOutputTimer.Start();
            }
        }

        private void Cancel(object sender, RoutedEventArgs e)
        {
            if (worker.IsBusy)
            {
                worker.CancelAsync();
            }
        }
    }
}
